package com.example.design.sercive;

import com.example.design.dutychain.AbstractBusinessHandler;
import com.example.design.dutychain.CityHandler;
import com.example.design.dutychain.builder.HandlerEnum;
import com.example.design.pojo.BusinessLaunch;
import com.example.design.pojo.UserInfo;
import com.example.design.repo.BusinessLaunchRepository;
import com.example.design.repo.UserRepository;
import com.example.design.ticket.proxy.DirectorProxy;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.List;

@Service
public class UserService {

    @Resource
    private UserRepository userRepository;

    @Resource
    private BusinessLaunchRepository businessLaunchRepository;

    //注入 duty.chain
    @Value("${duty.chain}")
    private String handleType;

    //记录当前handlerType的配置，判断duty.chain的配置是否有修改
    private String currentHandlerType;

    //记录当前的责任链头节点，如果配置没有修改，下次直接返回即可
    private AbstractBusinessHandler currentHandler;

    //代理类，增加银行卡信息验证
    @Resource
    private DirectorProxy directorProxy;


    //用户登录
    public String login(String userName, String userPassword) {
        UserInfo userInfo = userRepository.findByUserNameAndUserPassword(userName, userPassword);
        if (userInfo == null) {
            return "用户名或密码错误";
        }
        return "登录成功";
    }

    //用户注册
    public String register(UserInfo userInfo) {
        //判断用户名是否已存在,账号名称需要唯一
        if (isExist(userInfo.getUserName())) {
            return "用户名已存在";
        }
        //save方法
        userRepository.save(userInfo);

        return "注册成功";
    }

    public boolean isExist(String userName) {
        return userRepository.findByUserName(userName) != null;
    }


    public List<BusinessLaunch> filterBusinessLaunch(String city, String sex, String product) {
        List<BusinessLaunch> launchList = businessLaunchRepository.findAll();
        return buildChain().processHandler(launchList, city, sex, product);
    }


    //组装责任链条并返回责任链条头节点
    private AbstractBusinessHandler buildChain() {
        //如果没有配置，则直接返回null
        if (handleType == null) {
            return null;
        }
        //如果是第一次配置，则记录
        if (currentHandlerType == null) {
            this.currentHandlerType = this.handleType;
        }
        //说明duty.chain 的配置并未修改且currentHandler 不为null，直接返回currentHandler
        if (this.handleType.equals(currentHandlerType) && this.currentHandler != null) {
            return this.currentHandler;
        } else {
            //说明配置已修改，需要重新初始化责任链条
            //重新初始化责任链条，需要保证线程安全，仅仅每次修改配置时才会执行一次此处的代码，无性能问题
            System.out.println("duty.chain配置已修改，重新初始化责任链条");
            synchronized (this) {
                try {
                    //创建哑元节点，随便找一个具体责任类创建即可
                    AbstractBusinessHandler dummyHeadHandler = new CityHandler();
                    //创建前置节点，初始赋值为哑节点
                    AbstractBusinessHandler pre = dummyHeadHandler;
                    //将duty.chain的配置用 逗号 分割为 list类型，并通过HandlerEnum创建责任类，并配置责任链条
                    List<String> handleTypeList = Arrays.asList(handleType.split(","));
                    for (String handleType : handleTypeList) {
                        AbstractBusinessHandler handler = (AbstractBusinessHandler) Class.forName(HandlerEnum.valueOf(handleType).getValue()).newInstance();
                        pre.nextHandler = handler;
                    }
                    //从新赋值新的责任链头节点
                    this.currentHandler = dummyHeadHandler.nextHandler;
                    //从新赋值修改后的配置
                    this.currentHandlerType = this.handleType;
                    //返回责任链头节点
                    return currentHandler;
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

    public Object createTicket(String type, String productId, String content, String title, String bankInfo, String taxId) {
        return directorProxy.buildTicket(type, productId, content, title, bankInfo, taxId);
    }
}
